#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/input.h>

#define TM1638DEV_NAME		"tm1638"
#define TM1638DEV_NUM		1
#define SCAN_SEC			50
#define LED_BREATH			0x8B

struct tm1638_st
{
	dev_t devID;
	int major;
	int minor;
	int stbGpio;
	int clkGpio;
	int dioGpio;
	struct cdev cdev;
	struct class *class;
	struct device *device;
	struct device_node *node;
	struct input_dev *inputdev;
	struct timer_list timer;
};
static struct tm1638_st tm1638Dev;
static u8 key_code[] = {KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7};
static void timer_func(struct timer_list *timer);

static void tm1638_write_byte(u8 data)
{
	int i=0;

	for(i=0;i<8;i++)
	{
		gpio_set_value(tm1638Dev.clkGpio, 0);
		if(data & (0x1<<i))
		{
			udelay(5);
			gpio_set_value(tm1638Dev.dioGpio, 1);
			udelay(5);
		}
		else
		{
			udelay(5);
			gpio_set_value(tm1638Dev.dioGpio, 0);
			udelay(5);
		}
		gpio_set_value(tm1638Dev.clkGpio, 1);
		udelay(5);
	}
	udelay(5);
	gpio_set_value(tm1638Dev.clkGpio, 1);
	gpio_set_value(tm1638Dev.dioGpio, 1);
}

static u8 tm1638_read_byte(void)
{
	int i=0;
	int ret=0;
	u8 temp=0;

	for(i=0;i<8;i++)
	{
		gpio_set_value(tm1638Dev.clkGpio, 0);
		udelay(5);
		gpio_set_value(tm1638Dev.clkGpio, 1);
		udelay(5);
		ret = gpio_get_value(tm1638Dev.dioGpio);
		if(ret==0)
		{}
		else
		{
			temp |=(0x1<<i);
		}
		udelay(5);
	}
	udelay(5);
	gpio_set_value(tm1638Dev.clkGpio, 1);
	gpio_set_value(tm1638Dev.dioGpio, 1);

	return temp;
}

static void tm1638_init_clear(void)
{
	int i=0;
	u8 clearData = 0x00;

	//设置模式(些数据地址自加1)
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(0x40);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);

	//写起始地址
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(0xC0);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);

	//清显示
	gpio_set_value(tm1638Dev.stbGpio, 0);
	for(i=0;i<16;i++)
	{
		tm1638_write_byte(clearData);
	}
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);

	//设置显示亮度
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(LED_BREATH);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);
}

static void tm1638_write_data(u8 *buff, int lenth)
{
	int i=0;

	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(0x44);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);

	//向指定地址些数据
	for(i=0;i<lenth;i++)
	{
		gpio_set_value(tm1638Dev.stbGpio, 0);
		tm1638_write_byte(0xC0|(i*2));
		tm1638_write_byte(buff[i]);
		gpio_set_value(tm1638Dev.stbGpio, 1);
		udelay(5);
	}

	//设置显示亮度
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(LED_BREATH);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);
}

static void tm1638_read_data(u8 *buff, int lenth)
{
	int i=0;

	gpio_set_value(tm1638Dev.stbGpio, 0);

	//设置读取按键
	tm1638_write_byte(0x42);
	udelay(5);
	gpio_direction_input(tm1638Dev.dioGpio);
	udelay(5);

	//读取按键
	for(i=0;i<lenth;i++)
	{
		buff[i] = tm1638_read_byte();
	}
	gpio_direction_output(tm1638Dev.dioGpio, 1);
	gpio_set_value(tm1638Dev.stbGpio, 1);
}

static void tm1638_Write_LED(unsigned char LED_flag)
{
	u8 i;
	
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(0x44);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);
	
	for(i=0;i<8;i++)
	{
		gpio_set_value(tm1638Dev.stbGpio, 0);
		tm1638_write_byte((0xC0|(i*2))+1);
		if(LED_flag&(1<<i))
		{
			tm1638_write_byte(0x1);
		}
		else
		{
			tm1638_write_byte(0x0);
		}
		gpio_set_value(tm1638Dev.stbGpio, 1);
		udelay(5);
	}

	//设置显示亮度
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(LED_BREATH);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	udelay(5);
}

static ssize_t tm1638_write(struct file *flip, const char __user *buff, size_t cnt, loff_t *off_t)
{
	int lenth =0;
	int ret =0;
	u8 data_buff[9]= {0};

	if(cnt >9) 
		lenth =9;
	else 
		lenth = cnt;
	
	ret = copy_from_user(data_buff, buff, lenth);
	if(ret <0)
	{
		printk("copy_from_user error\r\n");
		return -EINVAL;
	}

	tm1638_Write_LED(data_buff[8]);
	tm1638_write_data(data_buff, 8);

	return 0;
}

static int tm1638_open(struct inode *inode, struct file *flip)
{
	//显示清零
	tm1638_init_clear();
	tm1638_Write_LED(0);

	//设置定时器
	timer_setup(&tm1638Dev.timer, timer_func, 0);

	//启动定时器
	mod_timer(&tm1638Dev.timer, jiffies+msecs_to_jiffies(SCAN_SEC));

	return 0;
}

static int tm1638_release(struct inode *inode, struct file *flip)
{
	//显示清零
	tm1638_init_clear();
	tm1638_Write_LED(0);

	//删除定时器
	del_timer_sync(&tm1638Dev.timer);

	return 0;
}

static void timer_func(struct timer_list *timer)
{
	int i =0;
	u8 key_buff[4]={0};
	static u8 buff[4]={0};

	tm1638_read_data(key_buff,4);
	if((buff[0]!=key_buff[0])||(buff[1]!=key_buff[1])||(buff[2]!=key_buff[2])||(buff[3]!=key_buff[3]))
	{
		for(i=0;i<4;i++)
		{
			if(key_buff[i]== 0x01)
			{
				input_report_key(tm1638Dev.inputdev, key_code[i], 1);
				input_sync(tm1638Dev.inputdev);
				input_report_key(tm1638Dev.inputdev, key_code[i], 0);
				input_sync(tm1638Dev.inputdev);
			}
			else if(key_buff[i]== 0x10)
			{
				input_report_key(tm1638Dev.inputdev, key_code[i+4], 1);
				input_sync(tm1638Dev.inputdev);
				input_report_key(tm1638Dev.inputdev, key_code[i+4], 0);
				input_sync(tm1638Dev.inputdev);
			}
			else if(key_buff[i]== 0x11)
			{
				input_report_key(tm1638Dev.inputdev, key_code[i], 1);
				input_sync(tm1638Dev.inputdev);
				input_report_key(tm1638Dev.inputdev, key_code[i], 0);
				input_sync(tm1638Dev.inputdev);
				input_report_key(tm1638Dev.inputdev, key_code[i+4], 1);
				input_sync(tm1638Dev.inputdev);
				input_report_key(tm1638Dev.inputdev, key_code[i+4], 0);
				input_sync(tm1638Dev.inputdev);
			}
		}
	}
	memcpy(buff, key_buff, 4);

	mod_timer(&tm1638Dev.timer, jiffies+msecs_to_jiffies(SCAN_SEC));
}

static const struct file_operations tm1638_ops = 
{
	.owner 		= THIS_MODULE,
	.open 		= tm1638_open,
	.release 	= tm1638_release,
	.write 		= tm1638_write,
};

static int tm1638_gpio_init(struct platform_device *dev)
{
	int ret =0;

	//提取节点
	tm1638Dev.node = dev->dev.of_node;
	
	//提取GPIO
	tm1638Dev.stbGpio = of_get_named_gpio(tm1638Dev.node, "gpios", 0);
	if(tm1638Dev.stbGpio <0)
	{
		printk("of_get_named_gpio error\r\n");
		ret = -EINVAL;
		goto getGpio_error;
	}
	
	tm1638Dev.clkGpio = of_get_named_gpio(tm1638Dev.node, "gpios", 1);
	if(tm1638Dev.clkGpio <0)
	{
		printk("of_get_named_gpio error\r\n");
		ret = -EINVAL;
		goto getGpio_error;
	}
			
	tm1638Dev.dioGpio = of_get_named_gpio(tm1638Dev.node, "gpios", 2);
	if(tm1638Dev.dioGpio <0)
	{
		printk("of_get_named_gpio error\r\n");
		ret = -EINVAL;
		goto getGpio_error;
	}

	//申请GPIO
	ret = gpio_request(tm1638Dev.stbGpio, "stbGpio");
	if(ret <0)
	{
		printk("gpio_request error\r\n");
		ret = -EINVAL;
		goto stbGpio_error;
	}
		
	ret = gpio_request(tm1638Dev.clkGpio, "clkGpio");
	if(ret <0)
	{
		printk("gpio_request error\r\n");
		ret = -EINVAL;
		goto clkGpio_error;
	}
			
	ret = gpio_request(tm1638Dev.dioGpio, "dioGpio");
	if(ret <0)
	{
		printk("gpio_request error\r\n");
		ret = -EINVAL;
		goto dioGpio_error;
	}
		
	//设置GPIO
	gpio_direction_output(tm1638Dev.stbGpio, 1);
	gpio_direction_output(tm1638Dev.clkGpio, 1);
	gpio_direction_output(tm1638Dev.dioGpio, 1);
	
	return 0;
	
dioGpio_error:
	gpio_free(tm1638Dev.clkGpio);
clkGpio_error:
	gpio_free(tm1638Dev.stbGpio);
stbGpio_error:
getGpio_error:
	return ret;
}

static int tm1638_probe(struct platform_device *dev)
{
	int ret=0;
	int i=0;

	//初始化GPIO
	ret = tm1638_gpio_init(dev);
	if(ret <0)
	{
		printk("tm1638_gpio_init error\r\n");
		ret = -EINVAL;
		goto gpio_err;
	}

	//申请设备号
	if(tm1638Dev.major)
	{
		tm1638Dev.devID = MKDEV(tm1638Dev.major, 0);
		ret = register_chrdev_region(tm1638Dev.devID, TM1638DEV_NUM, TM1638DEV_NAME);
		if(ret <0)
		{
			printk("register_chrdev_region error\r\n");
			ret = -EINVAL;
			goto chrdev_err;
		}
	}
	else
	{
		ret = alloc_chrdev_region(&tm1638Dev.devID, 0, TM1638DEV_NUM, TM1638DEV_NAME);
		if(ret <0)
		{
			printk("alloc_chrdev_region error\r\n");
			ret = -EINVAL;
			goto chrdev_err;
		}
		tm1638Dev.major = MAJOR(tm1638Dev.devID);
		tm1638Dev.minor = MINOR(tm1638Dev.devID);
	}

	//创建字符设备
	tm1638Dev.cdev.owner = THIS_MODULE;
	cdev_init(&tm1638Dev.cdev, &tm1638_ops);
	ret = cdev_add(&tm1638Dev.cdev, tm1638Dev.devID, TM1638DEV_NUM);
	if(ret<0)
	{
		printk("cdev_add error\r\n");
		ret = -EINVAL;
		goto cdev_err;
	}

	//创建类
	tm1638Dev.class = class_create(THIS_MODULE, TM1638DEV_NAME);
	if(IS_ERR(tm1638Dev.class))
	{
		printk("class_create error\r\n");
		ret = PTR_ERR(tm1638Dev.class);
		goto class_err;
	}

	//创建设备
	tm1638Dev.device = device_create(tm1638Dev.class, NULL, tm1638Dev.devID, NULL, TM1638DEV_NAME);
	if(IS_ERR(tm1638Dev.device))
	{
		printk("device_create error\r\n");
		ret = PTR_ERR(tm1638Dev.device);
		goto device_err;
	}

	//创建输入设备
	tm1638Dev.inputdev = input_allocate_device();
	if(IS_ERR(tm1638Dev.inputdev))
	{
		printk("input_allocate_device error\r\n");
		ret = PTR_ERR(tm1638Dev.inputdev);
		goto inputdev_err;
	}
	
	//设置输入事件
	__set_bit(EV_KEY, tm1638Dev.inputdev->evbit);
//	__set_bit(EV_REP, tm1638Dev.inputdev->evbit);
	for(i=0;i<8;i++)
	{
		__set_bit(key_code[i], tm1638Dev.inputdev->keybit);
	}
	
	//注册输入设备
	ret = input_register_device(tm1638Dev.inputdev);
	if(ret<0)
	{
		printk("input_register_device error\r\n");
		ret = -EINVAL;
		goto inputRegister_err;
	}

	printk("tm1638_probe sucess\r\n");
	return 0;

inputRegister_err:
	input_free_device(tm1638Dev.inputdev);
inputdev_err:
	device_destroy(tm1638Dev.class, tm1638Dev.devID);
device_err:
	class_destroy(tm1638Dev.class);
class_err:
	cdev_del(&tm1638Dev.cdev);
cdev_err:
	unregister_chrdev_region(tm1638Dev.devID, TM1638DEV_NUM);
chrdev_err:
gpio_err:
	return ret;
}

static int tm1638_remove(struct platform_device *dev)
{
	//关闭数码管显示
	gpio_set_value(tm1638Dev.stbGpio, 0);
	tm1638_write_byte(0x80);
	gpio_set_value(tm1638Dev.stbGpio, 1);
	
	//释放GPIO
	gpio_free(tm1638Dev.dioGpio);
	gpio_free(tm1638Dev.clkGpio);
	gpio_free(tm1638Dev.stbGpio);

	//销毁字符设备
	unregister_chrdev_region(tm1638Dev.devID, TM1638DEV_NUM);
	cdev_del(&tm1638Dev.cdev);

	//销毁设备
	device_destroy(tm1638Dev.class, tm1638Dev.devID);
	class_destroy(tm1638Dev.class);

	//销毁输入设备
	input_unregister_device(tm1638Dev.inputdev);
	input_free_device(tm1638Dev.inputdev);

	printk("tm1638_remove sucess\r\n");
	return 0;
}

static const struct platform_device_id tm1638_id[]=
{
	{"tm1638",0},
	{}
};

static const struct of_device_id tm1638_of_match[]=
{
	{.compatible = "tm1638"},
	{}
};

static struct platform_driver tm1638_dev = 
{
	.probe  = tm1638_probe,
	.remove = tm1638_remove,
	.driver = {
		.name  = "tm1638",
		.owner = THIS_MODULE,
		.of_match_table = tm1638_of_match,
	},
	.id_table = tm1638_id,
};

static int __init tm1638_init(void)
{
	return platform_driver_register(&tm1638_dev);
}

static void __exit tm1638_exit(void)
{
	platform_driver_unregister(&tm1638_dev);
}

module_init(tm1638_init);
module_exit(tm1638_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");

